#pragma once

#include <list>
#include <iostream>
#include "../Api-Blli/ApiBlli.h"
#include "Blli.h"
#include "AbsMutex.h"

class Universe;
struct EvalRoutineParameters
{
	EvalRoutineParameters(Universe* _universe, ApiBlli::Robot* _robot)
	{
		this->_Universe = _universe;
		this->_Robot = _robot;
	}

	Universe*		_Universe;
	ApiBlli::Robot*	_Robot;
};

struct SortByScore
{ 
   bool operator ()(Blli* a1, Blli* a2) 
   { 
	  return a1->GetScore() < a2->GetScore(); 
   } 
};

struct Measure
{
	~Measure()
	{
		for (int i = 0; i < 18; ++i)
		{
			delete _ServoPostion[i];
		}
		delete _BodyPosition;
	}
	bool					_Colision[6];
	float					_Torque[18];
	int						_MovementEnd[18];
	bool					_LegTouchingGround[6];
	bool					_BodyTouchingGround;
	ApiBlli::Position*		_ServoPostion[18];
	ApiBlli::Position*		_FingerPostion[6];
	ApiBlli::Position*		_BodyPosition;
	ApiBlli::GyroValues*	_GyroValues;
};

class Universe
{
public:
	Universe(const std::list<Blli*>& _initPopulation, const std::list<ApiBlli::Robot*>& _robots, std::map<int, int> _symmetry);
	~Universe(void);

	void	CreateLife();

private:
	std::list<ApiBlli::Robot*>	_Robots;
	std::list<Blli*>			_Population;
	std::list<Blli*>			_PopulationEvaluated;
	std::list<Blli*>			_PopulationEvaluatedAndSortedByScore;
	size_t						_PopulationSize;
	AbsMutex					_MutexGetNextBlli;
	AbsMutex					_MutexCloseBlli;
	Blli*						_TheBest;
	std::map<int, int>			_Symmetry;

	void			EvalPopulation();
	static void*	EvalPopulationRoutine(void* param);
	Blli*			GetNextBlli();
	void			CloseBlli(Blli* _blli);

	void			Selection(Blli** _mother, Blli** _father);
	Blli*			RouletteWheel();
	Blli*			CrossBlli(Blli* mother, Blli* father);
	Blli*			Mutate(std::map<int, float**>& _luts);

	static float	CalcDistance(const std::map<int, Measure*>& measures);
	static float	CalcDistanceUnitCost(const std::map<int, Measure*>& measures);
	static float	EvalEfficiency(const std::map<int, Measure*>& measures);

	static float	CalcTrajectoryFitness(const std::map<int, Measure*>& measures);
	static float	CalcDirectionFitness(const std::map<int, Measure*>& measures);
	static float	EvalGoodWay(const std::map<int, Measure*>& measures);

	static float	CalcGravityCenter(const std::map<int, Measure*>& measures);
	static float	CalcVerticalVariation(const std::map<int, Measure*>& measures);
	static float	CalcHorizontalTilt(const std::map<int, Measure*>& measures);
	static float	EvalBodyStability(const std::map<int, Measure*>& measures);

	static float	CalcLegsCollisions(const std::map<int, Measure*>& measures);
	static float	CalcBodyCollisions(const std::map<int, Measure*>& measures);
	static float	EvalRobotSecurity(const std::map<int, Measure*>& measures);

	static float	EvalScore(const std::map<int, Measure*>& measures, std::string& log);
};
